#include "BondCDCPriceInfo.h"

#include <core/Utility.h>
#include <core/time/date.h>
#include <qglobal.h>
#include <uam/ServerTimeMgr.h>

#include "BondCalendar.h"
#include "BondContainer.h"

CBondCDCPriceInfo::CBondCDCPriceInfo() { m_mpCdcContainer.reserve(1024 * 64); }

CBondCDCPriceInfo& CBondCDCPriceInfo::instance() {
  static CBondCDCPriceInfo cdcpi;
  return cdcpi;
}

void CBondCDCPriceInfo::ClearAll() {
  SCOPED_LOCK(m_mutex);
  m_mpCdcContainer.clear();
  m_updateDate = 0;
  m_updateDateSpec = 0;
}

void CBondCDCPriceInfo::ClearNonSpecial() {
  SCOPED_LOCK(m_mutex);
  std::unordered_map<int, CBondCdcPriceUnit>::iterator it =
      m_mpCdcContainer.begin();
  for (; it != m_mpCdcContainer.end();) {
    if (!it->second.isSpecial()) {
      it = m_mpCdcContainer.erase(it);
    } else
      it++;
  }
  m_updateDate = 0;
}

void CBondCDCPriceInfo::ClearSpecial() {
  SCOPED_LOCK(m_mutex);
  std::unordered_map<int, CBondCdcPriceUnit>::iterator it =
      m_mpCdcContainer.begin();
  for (; it != m_mpCdcContainer.end();) {
    if (it->second.isSpecial()) {
      it = m_mpCdcContainer.erase(it);
    } else
      it++;
  }
  m_updateDateSpec = 0;
}

void CBondCDCPriceInfo::Add(const int nBondIndex,
                            const xQBACDCPriceUnit_c& unit,
                            bool bSpecial)  // 需要外部加锁
{
  int nPrcType = GetCdcPrcType(unit);
  CBondCdcPriceUnit& pu = m_mpCdcContainer[nBondIndex];
  pu.Add(nPrcType, unit, bSpecial);

  if (bSpecial)
    m_updateDateSpec = qMax(m_updateDateSpec, unit.m_Date);
  else
    m_updateDate = qMax(m_updateDate, unit.m_Date);
}

uint32_t CBondCDCPriceInfo::GetEstimateDate(const int nBondIndex) {
  SCOPED_LOCK(m_mutex);
  std::unordered_map<int, CBondCdcPriceUnit>::iterator it =
      m_mpCdcContainer.find(nBondIndex);
  if (it == m_mpCdcContainer.end()) return 0;
  CBondCdcPriceUnit& bondCdc = it->second;
  return bondCdc.GetEstimateDate();
}

int CBondCDCPriceInfo::GetCdcPrcType(const xQBACDCPriceUnit_c& unit) {
  int nPriceType = est_type_null;
  QString priceType = QString::fromLocal8Bit(unit.m_est_option);
  if (priceType.compare("行权") == 0) {
    nPriceType = est_type_exercise;
  } else if (priceType.compare("到期") == 0) {
    nPriceType = est_type_expire;
  }
  return nPriceType;
}

bool CBondCDCPriceInfo::IsPriceValid(const char* pPrc, bool bIsCdc) {
  if (!pPrc) return false;
  if (pPrc[0] == '\0') return false;
  if (bIsCdc && strcmp(pPrc, "0") == 0) return false;
  if (!bIsCdc && (strcmp(pPrc, "Bid") == 0 || strcmp(pPrc, "bid") == 0 ||
                  strcmp(pPrc, "ofr") == 0 || strcmp(pPrc, "Ofr") == 0))
    return false;
  return true;
}

std::string CBondCDCPriceInfo::GetSplit() {
  static std::string strSplit = "/";
  return strSplit;
}

std::string CBondCDCPriceInfo::GetCDCPriceYesterday(int& nOptType,
                                                    const bool bIsCdcAuthValid,
                                                    const int nBondIndex,
                                                    const int nPrcType,
                                                    bool bSingle) {
  std::string strPrc;
  char sPrc[11] = {0};
  nOptType = CBondCDCPriceInfo::est_type_invalid;
  if (!bIsCdcAuthValid) return sPrc;  // 无估值权限

  SCOPED_LOCK(m_mutex);
  std::unordered_map<int, CBondCdcPriceUnit>::const_iterator it =
      m_mpCdcContainer.find(nBondIndex);
  if (it == m_mpCdcContainer.end()) return sPrc;  // 无估值数据

  const CBondCdcPriceUnit& bondCdc = it->second;
  if (bondCdc.GetSize() == 0) return sPrc;  // 无估值数据

  uint32_t nDate = bondCdc.GetEstimateDate();
  if (nDate <= 0) return sPrc;  // 无估值数据

  bool bSpec = bondCdc.isSpecial();
  if (bSpec && nDate != m_updateDateSpec)
    return sPrc;
  else if (!bSpec && nDate != m_updateDate)
    return sPrc;  // 估值日期不匹配

  bool bYesterday = false;                         // 未获取今日估值
  if (isTodayDataValid(bSpec)) bYesterday = true;  // 今日估值有效时

  for (int i = CBondCDCPriceInfo::est_type_exercise; i <= est_type_null; ++i) {
    if (bondCdc.GetEstimateElement(sPrc, _countof(sPrc), i, nPrcType,
                                   bYesterday)) {
      if (sPrc[0] != '\0') {
        if (!strPrc.empty()) strPrc += GetSplit();
        strPrc += sPrc;
      }

      if (nOptType == CBondCDCPriceInfo::est_type_exercise &&
          i == CBondCDCPriceInfo::est_type_expire)
        nOptType = CBondCDCPriceInfo::est_type_combine;
      else
        nOptType = i;

      if (bSingle) break;
    }
  }
  return strPrc;
}

std::string CBondCDCPriceInfo::GetCDCPriceToday(int& nOptType,
                                                const bool bIsCdcAuthValid,
                                                const int nBondIndex,
                                                const int nPrcType,
                                                bool bSingle) {
  std::string strPrc;
  char sPrc[11] = {0};
  nOptType = CBondCDCPriceInfo::est_type_invalid;
  if (!bIsCdcAuthValid) return sPrc;  // 无估值权限

  SCOPED_LOCK(m_mutex);
  std::unordered_map<int, CBondCdcPriceUnit>::const_iterator it =
      m_mpCdcContainer.find(nBondIndex);
  if (it == m_mpCdcContainer.end()) return sPrc;  // 无估值数据

  const CBondCdcPriceUnit& bondCdc = it->second;
  if (bondCdc.GetSize() == 0) return sPrc;  // 无估值数据

  uint32_t nDate = bondCdc.GetEstimateDate();
  if (nDate <= 0) return sPrc;  // 无估值数据

  bool bSpec = bondCdc.isSpecial();
  if (bSpec && nDate != m_updateDateSpec)
    return sPrc;
  else if (!bSpec && nDate != m_updateDate)
    return sPrc;  // 估值日期不匹配

  if (!isTodayDataValid(bSpec)) return sPrc;  // 无今日数据

  for (int i = CBondCDCPriceInfo::est_type_exercise; i <= est_type_null; ++i) {
    if (bondCdc.GetEstimateElement(sPrc, _countof(sPrc), i, nPrcType, false)) {
      if (sPrc[0] != '\0') {
        if (!strPrc.empty()) strPrc += GetSplit();
        strPrc += sPrc;
      }

      if (nOptType == CBondCDCPriceInfo::est_type_exercise &&
          i == CBondCDCPriceInfo::est_type_expire)
        nOptType = CBondCDCPriceInfo::est_type_combine;
      else
        nOptType = i;

      if (bSingle) break;
    }
  }
  return strPrc;
}

std::string CBondCDCPriceInfo::GetCDCPriceLast(int& nOptType,
                                               const bool bIsCdcAuthValid,
                                               const int nBondIndex,
                                               const int nPrcType,
                                               bool bSingle) {
  std::string strPrc;
  char sPrc[11] = {0};
  nOptType = CBondCDCPriceInfo::est_type_invalid;
  if (!bIsCdcAuthValid) return sPrc;  // 无估值权限

  SCOPED_LOCK(m_mutex);
  std::unordered_map<int, CBondCdcPriceUnit>::const_iterator it =
      m_mpCdcContainer.find(nBondIndex);
  if (it == m_mpCdcContainer.end()) return sPrc;  // 无估值数据

  const CBondCdcPriceUnit& bondCdc = it->second;
  if (bondCdc.GetSize() == 0) return sPrc;  // 无估值数据

  uint32_t nDate = bondCdc.GetEstimateDate();
  if (nDate <= 0) return sPrc;  // 无估值数据

  bool bSpec = bondCdc.isSpecial();
  if (bSpec && nDate != m_updateDateSpec)
    return sPrc;
  else if (!bSpec && nDate != m_updateDate)
    return sPrc;  // 估值日期不匹配

  for (int i = CBondCDCPriceInfo::est_type_exercise; i <= est_type_null; ++i) {
    if (bondCdc.GetEstimateElement(sPrc, _countof(sPrc), i, nPrcType, false)) {
      if (sPrc[0] != '\0') {
        if (!strPrc.empty()) strPrc += GetSplit();
        strPrc += sPrc;
      }

      if (nOptType == CBondCDCPriceInfo::est_type_exercise &&
          i == CBondCDCPriceInfo::est_type_expire)
        nOptType = CBondCDCPriceInfo::est_type_combine;
      else
        nOptType = i;

      if (bSingle) break;
    }
  }
  return strPrc;
}

std::string CBondCDCPriceInfo::GetCDCPriceYesterdayByOpt(
    int& nOptType, const bool bIsCdcAuthValid, const int nBondIndex,
    const int nOptTypeStart, const int nPrcType) {
  char sPrc[11] = {0};
  nOptType = CBondCDCPriceInfo::est_type_invalid;
  if (!bIsCdcAuthValid) return sPrc;

  SCOPED_LOCK(m_mutex);
  std::unordered_map<int, CBondCdcPriceUnit>::const_iterator it =
      m_mpCdcContainer.find(nBondIndex);
  if (it == m_mpCdcContainer.end()) return sPrc;

  const CBondCdcPriceUnit& bondCdc = it->second;
  if (bondCdc.GetSize() == 0) return sPrc;

  uint32_t nDate = bondCdc.GetEstimateDate();
  if (nDate <= 0) return sPrc;  // 无估值数据

  bool bSpec = bondCdc.isSpecial();
  if (bSpec && nDate != m_updateDateSpec)
    return sPrc;
  else if (!bSpec && nDate != m_updateDate)
    return sPrc;  // 估值日期不匹配

  bool bYesterday = false;                         // 未获取今日估值
  if (isTodayDataValid(bSpec)) bYesterday = true;  // 今日估值有效时

  for (int i = nOptTypeStart; i <= est_type_null; ++i) {
    if (bondCdc.GetEstimateElement(sPrc, _countof(sPrc), i, nPrcType,
                                   bYesterday)) {
      if (sPrc[0] != '\0') {
        nOptType = i;
        break;
      }
    }
  }

  return sPrc;
}

std::string CBondCDCPriceInfo::GetRelaEstimatePrice(
    const bool bIsCdcAuthValid, const int nBondIndex,
    const int nPrcType /*= 0/*price_type_yield*/,
    const char* pRef /*= nullptr*/, bool bYesterday /*= false*/) {
  char sPrc[11] = {0};
  char sTmp[11] = {0};
  if (!bIsCdcAuthValid) return sPrc;
  bool bRefValid = IsPriceValid(pRef);
  {
    SCOPED_LOCK(m_mutex);
    std::unordered_map<int, CBondCdcPriceUnit>::iterator it =
        m_mpCdcContainer.find(nBondIndex);
    if (it == m_mpCdcContainer.end()) return sPrc;
    const CBondCdcPriceUnit& bondCdc = it->second;
    if (bondCdc.GetSize() == 0) return sPrc;
    double dGap = INVALID_CDC_VALUE;
    for (int i = CBondCDCPriceInfo::est_type_exercise; i <= est_type_null;
         ++i) {
      if (!bondCdc.GetEstimateElement(sTmp, _countof(sTmp), i, nPrcType,
                                      bYesterday))
        continue;
      if (!bRefValid && IsPriceValid(sTmp, true)) {
        FIELDCOPY(sPrc, sTmp);
        break;
      }
      bool bCalcuValid = IsPriceValid(sTmp, true) ? bRefValid : false;
      if (!bCalcuValid) {  // 保存的中债估值存在无效值
        continue;
      }
      double dTmp = atof(pRef) - atof(sTmp);
      if (abs(dTmp) > abs(dGap)) continue;
      dGap = dTmp;
      FIELDCOPY(sPrc, sTmp);
    }
  }
  return sPrc;
}

void CBondCDCPriceInfo::GetExerciseAndMaturity(const bool bIsCdcAuthValid,
                                               const int nBondIndex,
                                               double& dExercise,
                                               double& dMaturity) {
  dExercise = INVALID_CDC_VALUE;
  dMaturity = INVALID_CDC_VALUE;

  if (!bIsCdcAuthValid) return;

  SCOPED_LOCK(m_mutex);
  std::unordered_map<int, CBondCdcPriceUnit>::iterator itrFind =
      m_mpCdcContainer.find(nBondIndex);
  if (itrFind == m_mpCdcContainer.end()) return;

  char sPrc[11] = {0};

  CBondCdcPriceUnit& CdcUnit = itrFind->second;
  for (int i = CBondCDCPriceInfo::est_type_exercise; i <= est_type_null; ++i) {
    memset(sPrc, 0, sizeof(sPrc));

    if (i == est_type_exercise) {
      if (CdcUnit.GetEstimateElement(sPrc, sizeof(sPrc), i, price_type_yield,
                                     false) &&
          IsPriceValid(sPrc, true)) {
        dExercise = atof(sPrc);
      }
    } else if (i == est_type_expire) {
      if (CdcUnit.GetEstimateElement(sPrc, sizeof(sPrc), i, price_type_yield,
                                     false) &&
          IsPriceValid(sPrc, true)) {
        dMaturity = atof(sPrc);
      }
    }
  }

  if (dExercise <= INVALID_CDC_VALUE && dMaturity <= INVALID_CDC_VALUE) {
    if (CdcUnit.GetEstimateElement(sPrc, sizeof(sPrc), est_type_null,
                                   price_type_yield, false) &&
        IsPriceValid(sPrc, true))
      dMaturity = atof(sPrc);
  }
}

bool CBondCDCPriceInfo::isTodayDataValid(bool bSpec) {
  static uint32_t dateLastCalc = 0;
  static bool isHoliday = false;
  uint32_t today =
      qb::base::IntDate::timeToInt(ServerTimeMgr::instance().serverTime());
  if (today != dateLastCalc) {
    int nToday = (int)today;
    isHoliday = CBondCalendar::instance().IsHoliday("CNY", "CIB", nToday);
    dateLastCalc = today;
  }

  if (bSpec) {
    if (m_updateDateSpec ==
        qb::base::IntDate::timeToInt(
            ServerTimeMgr::instance().serverTime())) {  // 今日估值已收到
      return true;
    } else {  // 今日估值未收到
      if (isHoliday)
        return true;
      else
        return false;
    }
  } else {
    if (m_updateDate ==
        qb::base::IntDate::timeToInt(
            ServerTimeMgr::instance().serverTime())) {  // 今日估值已收到
      return true;
    } else {  // 今日估值未收到
      if (isHoliday)
        return true;
      else
        return false;
    }
  }

  return false;
}

double CBondCDCPriceInfo::GetYesterdayCDCPriceGap(
    const bool bIsCdcAuthValid, const int nBondIndex,
    const int nPrcType /*=price_type_yield*/, bool bReverse,
    const char* pRef /*= nullptr*/, const double dRef /*= INVALID_CDC_VALUE*/,
    bool bForceExercise /*=false*/) {
  char sPrc[11] = {0};
  if (!bIsCdcAuthValid) return INVALID_CDC_VALUE;
  if (!CBondContainer::instance().IsValidIndex(nBondIndex))
    return INVALID_CDC_VALUE;
  bool bRefValid = false;
  double dPrc = INVALID_CDC_VALUE;
  if (pRef == nullptr) {
    dPrc = dRef;
    bRefValid = true;
  } else {
    bRefValid = IsPriceValid(pRef);
    dPrc = atof(pRef);
  }
  bRefValid = (dPrc > INVALID_CDC_VALUE) ? bRefValid : false;
  double dGap = INVALID_CDC_VALUE;
  if (!bRefValid) return dGap;

  SCOPED_LOCK(m_mutex);
  std::unordered_map<int, CBondCdcPriceUnit>::iterator it =
      m_mpCdcContainer.find(nBondIndex);
  if (it == m_mpCdcContainer.end()) return dGap;

  const CBondCdcPriceUnit& bondCdc = it->second;
  if (bondCdc.GetSize() == 0) return dGap;  // 无估值数据

  uint32_t nDate = bondCdc.GetEstimateDate();
  if (nDate <= 0) return dGap;  // 无估值数据

  bool bSpec = bondCdc.isSpecial();
  if (bSpec && nDate != m_updateDateSpec)
    return dGap;
  else if (!bSpec && nDate != m_updateDate)
    return dGap;  // 估值日期不匹配

  bool bYesterday = false;                         // 未获取今日估值
  if (isTodayDataValid(bSpec)) bYesterday = true;  // 今日估值有效时

  for (int i = CBondCDCPriceInfo::est_type_exercise; i <= est_type_null; ++i) {
    if (bForceExercise && i == CBondCDCPriceInfo::est_type_expire) continue;
    if (!bondCdc.GetEstimateElement(sPrc, _countof(sPrc), i, nPrcType,
                                    bYesterday))
      continue;
    bool bCalcuValid = IsPriceValid(sPrc, true) ? bRefValid : false;
    if (!bCalcuValid) {  // 保存的中债估值存在无效值
      continue;
    }
    double dTmp = (bReverse ? dPrc - atof(sPrc) : atof(sPrc) - dPrc) * 100;
    if (fabs(dTmp) > fabs(dGap)) continue;
    dGap = dTmp;
  }

  return dGap;
}

double CBondCDCPriceInfo::GetYesterdayCDCCleanPriceGap(
    const bool bIsCdcAuthValid, const int nBondIndex,
    const int nPrcType /*=price_type_yield*/, bool bReverse /* = true*/,
    const char* pRef /* = nullptr*/, const double dRef /* = INVALID_CDC_VALUE*/,
    int exercise /*= -1*/) {
  char sPrc[11] = {0};
  if (!bIsCdcAuthValid) return INVALID_CDC_VALUE;
  if (!CBondContainer::instance().IsValidIndex(nBondIndex))
    return INVALID_CDC_VALUE;
  bool bRefValid = false;
  double dPrc = INVALID_CDC_VALUE;
  if (pRef == nullptr) {
    dPrc = dRef;
    bRefValid = true;
  } else {
    bRefValid = IsPriceValid(pRef);
    dPrc = atof(pRef);
  }
  bRefValid = (dPrc > INVALID_CDC_VALUE) ? bRefValid : false;
  double dGap = INVALID_CDC_VALUE;
  if (!bRefValid) return dGap;

  SCOPED_LOCK(m_mutex);
  std::unordered_map<int, CBondCdcPriceUnit>::iterator it =
      m_mpCdcContainer.find(nBondIndex);
  if (it == m_mpCdcContainer.end()) return dGap;

  const CBondCdcPriceUnit& bondCdc = it->second;
  if (bondCdc.GetSize() == 0) return dGap;  // 无估值数据

  UINT nDate = bondCdc.GetEstimateDate();
  if (nDate <= 0) return dGap;  // 无估值数据

  bool bSpec = bondCdc.isSpecial();
  if (bSpec && nDate != m_updateDateSpec)
    return dGap;
  else if (!bSpec && nDate != m_updateDate)
    return dGap;  // 估值日期不匹配

  bool bYesterday = false;                         // 未获取今日估值
  if (isTodayDataValid(bSpec)) bYesterday = true;  // 今日估值有效时

  bool bCalcuValid = false;
  switch (exercise) {
    case 0:  // 行权
      if (!bondCdc.GetEstimateElement(sPrc, _countof(sPrc),
                                      CBondCDCPriceInfo::est_type_exercise,
                                      nPrcType, bYesterday))
        break;
      if (!IsPriceValid(sPrc, true)) break;
      bCalcuValid = true;
      break;
    case 1:  // 到期
      if (!bondCdc.GetEstimateElement(sPrc, _countof(sPrc),
                                      CBondCDCPriceInfo::est_type_expire,
                                      nPrcType, bYesterday))
        break;
      if (!IsPriceValid(sPrc, true)) break;
      bCalcuValid = true;
      break;
    case -1:  // 不限，取绝对值最小偏离
    default:
      break;
  }

  if (!bCalcuValid) {
    for (int i = CBondCDCPriceInfo::est_type_exercise; i <= est_type_null;
         ++i) {
      if (!bondCdc.GetEstimateElement(sPrc, _countof(sPrc), i, nPrcType,
                                      bYesterday))
        continue;
      if (!IsPriceValid(sPrc, true)) continue;
      double dTmp = bReverse ? dPrc - atof(sPrc) : atof(sPrc) - dPrc;
      if (fabs(dTmp) > fabs(dGap)) continue;
      dGap = dTmp;
    }
  } else
    dGap = bReverse ? dPrc - atof(sPrc) : atof(sPrc) - dPrc;

  return dGap;
}

double CBondCDCPriceInfo::GetEstimatePriceGap(
    const bool bIsCdcAuthValid, const int nBondIndex,
    const int nPrcType /*= 0/*price_type_yield*/, bool bReverse,
    const char* pRef /*= nullptr*/, const double dRef /*= INVALID_CDC_VALUE*/,
    bool bYesterday /*= false*/, bool bForceExercise /*=false*/) {
  char sPrc[11] = {0};
  if (!bIsCdcAuthValid) return INVALID_CDC_VALUE;
  if (!CBondContainer::instance().IsValidIndex(nBondIndex))
    return INVALID_CDC_VALUE;
  bool bRefValid = false;
  double dPrc = INVALID_CDC_VALUE;
  if (pRef == nullptr) {
    dPrc = dRef;
    bRefValid = true;
  } else {
    bRefValid = IsPriceValid(pRef);
    dPrc = atof(pRef);
  }
  bRefValid = (dPrc > INVALID_CDC_VALUE) ? bRefValid : false;
  double dGap = INVALID_CDC_VALUE;
  if (!bRefValid) return dGap;
  {
    SCOPED_LOCK(m_mutex);
    std::unordered_map<int, CBondCdcPriceUnit>::iterator it =
        m_mpCdcContainer.find(nBondIndex);
    if (it == m_mpCdcContainer.end()) return dGap;
    CBondCdcPriceUnit& bondCdc = it->second;
    for (int i = CBondCDCPriceInfo::est_type_exercise; i <= est_type_null;
         ++i) {
      if (bForceExercise && i == CBondCDCPriceInfo::est_type_expire) continue;
      if (!bondCdc.GetEstimateElement(sPrc, _countof(sPrc), i, nPrcType,
                                      bYesterday))
        continue;
      bool bCalcuValid = IsPriceValid(sPrc, true) ? bRefValid : false;
      if (!bCalcuValid) {  // 保存的中债估值存在无效值
        continue;
      }
      double dTmp = (bReverse ? dPrc - atof(sPrc) : atof(sPrc) - dPrc) * 100;
      if (fabs(dTmp) > fabs(dGap)) continue;
      dGap = dTmp;
    }
  }
  return dGap;
}

CBondCdcPriceUnit::CBondCdcPriceUnit() : m_bSpecial(false) {}

void CBondCdcPriceUnit::Add(const int nPrcType, const xQBACDCPriceUnit_c& unit,
                            bool bSpecial) {
  static sCDCPrice uEmpty;
  auto it = m_mpBondCdc.find(nPrcType);
  if (it == m_mpBondCdc.end()) {
    m_mpBondCdc.insert(nPrcType, uEmpty);
    it = m_mpBondCdc.find(nPrcType);
  }
  if (it == m_mpBondCdc.end()) return;
  if (it->second.m_nEstDate > unit.m_Date)
    return;
  else if (it->second.m_nEstDate ==
           unit.m_Date) {  // 同时有效，则使用标准表数据
    if (bSpecial && !m_bSpecial) return;
    if (!bSpecial &&
        m_bSpecial) {  // 如果缓存数据为special表数据，需清空数据，因为special表没有含权数据
      m_mpBondCdc.clear();
      m_mpBondCdc.insert(nPrcType, uEmpty);
      it = m_mpBondCdc.find(nPrcType);
      if (it == m_mpBondCdc.end()) return;
    }
  } else  // cdcUnit.m_nEstDate < unit.m_Date
  {
    if (bSpecial !=
        m_bSpecial) {  // 如果缓存数据为前一天数据，并且来源不是同一张表，需清空数据，因为special表没有含权信息
      m_mpBondCdc.clear();
      m_mpBondCdc.insert(nPrcType, uEmpty);
      it = m_mpBondCdc.find(nPrcType);
      if (it == m_mpBondCdc.end()) return;
    }
  }
  sCDCPrice& cdcUnit = it->second;
  FIELDCOPY(cdcUnit.m_sEstcleanprice, unit.m_CleanPrice);
  FIELDCOPY(cdcUnit.m_sEstPrice, unit.m_Yield);
  FIELDCOPY(cdcUnit.m_sFrontEstcleanprice, unit.m_FrontCleanPrice);
  FIELDCOPY(cdcUnit.m_sFrontEstPrice, unit.m_FrontYield);
  FIELDCOPY(cdcUnit.m_sDuration, unit.m_Duration);
  cdcUnit.m_nEstDate = unit.m_Date;
  m_bSpecial = bSpecial;
  return;

  // 	sCDCPrice &cdcUnit = m_mpBondCdc[nPrcType];
  // 	if (cdcUnit.m_nEstDate > unit.m_Date)return;
  // 	else if (cdcUnit.m_nEstDate == unit.m_Date)
  // 	{//同时有效，则使用标准表数据
  // 		if (bSpecial && !m_bSpecial)return;
  // 		if (!bSpecial && m_bSpecial)
  // 		{//如果缓存数据为special表数据，需清空数据，因为special表没有含权数据
  // 			m_mpBondCdc.clear();
  // 			sCDCPrice &cdcUnit2 = m_mpBondCdc[nPrcType];
  // 			FIELDCOPY(cdcUnit2.m_sEstcleanprice, unit.m_CleanPrice);
  // 			FIELDCOPY(cdcUnit2.m_sEstPrice, unit.m_Yield);
  // 			FIELDCOPY(cdcUnit2.m_sFrontEstcleanprice,
  // unit.m_FrontCleanPrice);
  // FIELDCOPY(cdcUnit2.m_sFrontEstPrice, unit.m_FrontYield);
  // FIELDCOPY(cdcUnit2.m_sDuration, unit.m_Duration); 			cdcUnit2.m_nEstDate =
  // unit.m_Date; 			m_bSpecial = bSpecial; 			return;
  // 		}
  // 	}
  // 	else// cdcUnit.m_nEstDate < unit.m_Date
  // 	{
  // 		if (bSpecial != m_bSpecial)
  // 		{//如果缓存数据为前一天数据，并且来源不是同一张表，需清空数据，因为special表没有含权信息
  // 			m_mpBondCdc.clear();
  // 			sCDCPrice &cdcUnit2 = m_mpBondCdc[nPrcType];
  // 			FIELDCOPY(cdcUnit2.m_sEstcleanprice, unit.m_CleanPrice);
  // 			FIELDCOPY(cdcUnit2.m_sEstPrice, unit.m_Yield);
  // 			FIELDCOPY(cdcUnit2.m_sFrontEstcleanprice,
  // unit.m_FrontCleanPrice);
  // FIELDCOPY(cdcUnit2.m_sFrontEstPrice, unit.m_FrontYield);
  // FIELDCOPY(cdcUnit2.m_sDuration, unit.m_Duration); 			cdcUnit2.m_nEstDate =
  // unit.m_Date; 			m_bSpecial = bSpecial; 			return;
  // 		}
  // 	}
  // 	FIELDCOPY(cdcUnit.m_sEstcleanprice, unit.m_CleanPrice);
  // 	FIELDCOPY(cdcUnit.m_sEstPrice, unit.m_Yield);
  // 	FIELDCOPY(cdcUnit.m_sFrontEstcleanprice, unit.m_FrontCleanPrice);
  // 	FIELDCOPY(cdcUnit.m_sFrontEstPrice, unit.m_FrontYield);
  // 	FIELDCOPY(cdcUnit.m_sDuration, unit.m_Duration);
  // 	cdcUnit.m_nEstDate = unit.m_Date;
  // 	m_bSpecial = bSpecial;
  // 	return;
}

bool CBondCdcPriceUnit::GetEstimateElement(char* const estPrice,
                                           const int capacity,
                                           const int nOptType,
                                           const int nPrcType /*= 0*/,
                                           bool bYesterday /*= false*/) const {
  auto it = m_mpBondCdc.find(nOptType);
  if (it == m_mpBondCdc.end()) return false;
  const char* src = it->second.m_sEstPrice;
  switch (nPrcType) {
    case CBondCDCPriceInfo::price_type_yield: {
      if (bYesterday) src = it->second.m_sFrontEstPrice;
      break;
    }
    case CBondCDCPriceInfo::price_type_clean: {
      if (!bYesterday)
        src = it->second.m_sEstcleanprice;
      else
        src = it->second.m_sFrontEstcleanprice;
      if (strcmp(src, "0.0000") == 0) src = NULL;
      break;
    }
    case CBondCDCPriceInfo::price_type_duration: {
      src = it->second.m_sDuration;
      break;
    }
    default:
      break;
  }
#if WIN32
  if (src) strncpy_s(estPrice, capacity, src, _TRUNCATE);
#else
  if (src) {
    strncpy(estPrice, src, capacity);
    estPrice[capacity - 1] = '\0';
  }
#endif

  if (!src || *src == '\0') return false;
  return true;
}

uint32_t CBondCdcPriceUnit::GetEstimateDate() const {
  for (int i = CBondCDCPriceInfo::est_type_exercise;
       i <= CBondCDCPriceInfo::est_type_null; ++i) {
    auto it = m_mpBondCdc.find(i);
    if (it == m_mpBondCdc.end()) continue;
    return it->second.m_nEstDate;
  }

  return 0;
}

int CBondCdcPriceUnit::GetSize() const { return m_mpBondCdc.size(); }

bool CBondCdcPriceUnit::isSpecial() const { return m_bSpecial; }

CBondCdcPriceUnit::CDCPriceVec::const_iterator
CBondCdcPriceUnit::CDCPriceVec::find(int optionType) const {
  for (auto it = m_values.cbegin(); it != m_values.cend(); ++it) {
    if (it->first == optionType) return it;
  }
  return m_values.cend();
}
CBondCdcPriceUnit::CDCPriceVec::iterator CBondCdcPriceUnit::CDCPriceVec::find(
    int optionType) {
  for (auto it = m_values.begin(); it != m_values.end(); ++it) {
    if (it->first == optionType) return it;
  }
  return m_values.end();
}
void CBondCdcPriceUnit::CDCPriceVec::insert(int optionType,
                                            const sCDCPrice& price) {
  for (auto it = m_values.begin(); it != m_values.end(); ++it) {
    if (it->first == optionType) {
      memcpy(&(it->second), &price, sizeof(price));
      return;
    }
  }
  // 为防止m_values扩张浪费多余的空间,节省内存,禁用vector内嵌的1/2扩容机制
  if (m_values.size() >= m_values.capacity())
    m_values.reserve(m_values.capacity() + 1);
  m_values.emplace_back(KeyValue{optionType, price});
}
sCDCPrice& CBondCdcPriceUnit::CDCPriceVec::operator[](int optionType) {
  for (auto it = m_values.begin(); it != m_values.end(); ++it) {
    if (it->first == optionType) {
      return it->second;
    }
  }
  // 为防止m_values扩张浪费多余的空间,节省内存,禁用vector内嵌的1/2扩容机制
  if (m_values.size() >= m_values.capacity())
    m_values.reserve(m_values.capacity() + 1);
  m_values.emplace_back(KeyValue{optionType, sCDCPrice{}});
  return m_values[m_values.size() - 1].second;
}
